package com.lmxdawn.api.dnf.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayFundTransUniTransferModel;
import com.alipay.api.domain.Participant;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lmxdawn.api.admin.entity.auth.AuthAdmin;
import com.lmxdawn.api.admin.service.auth.AuthAdminService;
import com.lmxdawn.api.common.session.SessionContextHolder;
import com.lmxdawn.api.dnf.entity.*;
import com.lmxdawn.api.dnf.mapper.ExtraApplyMapper;
import com.lmxdawn.api.dnf.service.IAlipayAccountService;
import com.lmxdawn.api.dnf.service.IChargeConfigService;
import com.lmxdawn.api.dnf.service.IExtraApplyService;
import com.lmxdawn.api.dnf.service.IRealnameService;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import lombok.var;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class ExtraApplyServiceImpl extends ServiceImpl<ExtraApplyMapper, ExtraApply> implements IExtraApplyService {

    @Resource
    IRealnameService realnameService;

    @Resource
    RedissonClient redissonClient;
    @Resource
    IChargeConfigService chargeConfigService;

    @Resource
    IAlipayAccountService accountService;
    @Autowired
    private AuthAdminService userService;
    @Autowired
    private UserBillServiceImpl userBillServiceImpl;
    @Autowired
    private WithdrawAccountServiceImpl withdrawAccountServiceImpl;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public ExtraApply doExtra(ExtraApply apply, String id) throws AlipayApiException {
        // 2、调用支付宝或者微信进行转账请求
        val lock = redissonClient.getLock("EXTRA_LOCK");
        if (!lock.tryLock()) {
            throw new RuntimeException("系统繁忙，请稍后再试");
        }
        try {
            ExtraApply extraApply = this.getById(apply.getId());
            extraApply.setUpdateBy(id);
            extraApply.setUpdateTime(new Date());
            log.info("do extra apply:{},{}", extraApply.getAmount(), extraApply.getAccount());
            if (extraApply.getStatus() != 0) {
                throw new RuntimeException("该提现申请不能重复审批");
            }
            if (apply.getStatus() == 2) {
                return this.reject(extraApply);
            }

            extraApply.setStatus(1);
            String userId = extraApply.getUserId();
            AuthAdmin user = userService.findById(userId);
            String balanceStr = user.getBalance();
            BigDecimal balance = new BigDecimal(balanceStr);
            log.info("do extra apply :{},balance:{}", extraApply.getAmount(), balance);

//        if (balance.compareTo(apply.getAmount()) < 0) {
//            throw new RuntimeException("用户余额不足");
//        }
            BigDecimal extra = this.doExtract(user, extraApply);
            extraApply.setRes(extra.compareTo(extraApply.getAmount()) == 0
                    ? 1 : (extra.compareTo(BigDecimal.ZERO) == 0 ? 0 : 2));
            //
            this.updateById(extraApply);
            // 350 提现300  成功100 失败200  则实际余额 = 250
            //  50 + 300 - 100 = 250
            log.info("用户： {}， 提现：{}，成功：{}， 原余额：{}", user.getUsername(),
                    extra, extraApply.getAmount(), balance);
            // 提现失败的情况  extra = 0
            if (extra.compareTo(extraApply.getAmount()) < 0) {
                extraApply.setStatus(3);
                var subtract = balance.add(extraApply.getAmount()).subtract(extra);
                user.setBalance(subtract.toString());
                userService.updateAuthAdmin(user);
            } else {
                UserBill userBill = new UserBill();
                userBill.setUserId(user.getId());
                userBill.setAmount(extraApply.getAmount());
                userBill.setBalance(user.getBalance());
                userBill.setCreateTime(new Date());
                userBill.setType("提现转出");
                userBillServiceImpl.save(userBill);
            }
            this.updateById(extraApply);
            return extraApply;
        }catch (Exception e){
            return null;
        }
        finally {
            lock.unlock();
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ExtraApply reject(ExtraApply extraApply) {
//        ExtraApply extraApply = this.getById(apply.getId());
        extraApply.setStatus(2);
        String userId = extraApply.getUserId();
        AuthAdmin user = userService.findById(userId);
        String balance = user.getBalance();
        BigDecimal bigDecimal = new BigDecimal(balance);
        user.setBalance(bigDecimal.add(extraApply.getAmount()).toString());
        userService.updateAuthAdmin(user);
        this.updateById(extraApply);
        return extraApply;
    }


    private AlipayConfig getConfig(AuthAdmin user) {
        var accountList = accountService.lambdaQuery().list();
        long slot = 0;//userId % size;  todo
        var alipayAccount = accountList.get((int) slot);
        AlipayConfig alipayConfig = new AlipayConfig();
//设置网关地址
        alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do");
//设置应用APPID
        alipayConfig.setAppId(alipayAccount.getAppId());
//设置应用私钥
        alipayConfig.setPrivateKey(alipayAccount.getPrivateKey());
//设置应用公钥证书路径
        alipayConfig.setAppCertPath("/certs/" + alipayAccount.getAppId() + "/appCertPublicKey.crt");
//设置支付宝公钥证书路径
        alipayConfig.setAlipayPublicCertPath("/certs/" + alipayAccount.getAppId() + "/alipayCertPublicKey_RSA2.crt");
//设置支付宝根证书路径
        alipayConfig.setRootCertPath("/certs/" + alipayAccount.getAppId() + "/alipayRootCert.crt");
//设置请求格式，固定值json
        alipayConfig.setFormat("json");
//设置字符集
        alipayConfig.setCharset("utf-8");
        return alipayConfig;
    }


    private BigDecimal doExtract(AuthAdmin user, ExtraApply content) throws AlipayApiException {
        BigDecimal extra = BigDecimal.ZERO;
        // 提现手续费计算 比如后台设定0.9% 99元提现最低2元手续费 即打款97元
        // 提现最低2元手续费 最高50元
        // 手续费500元就是 500*0.9% 4.5手续费 到账495.5 1万元正常是90手续费 但是最高收50 也就是扣50
        BigDecimal amount = content.getAmount();
        BigDecimal charge = StrUtil.isNotBlank(content.getFee()) ? new BigDecimal(content.getFee()) : BigDecimal.ZERO;
//        ChargeConfig chargeConfig = chargeConfigService.lambdaQuery().eq(ChargeConfig::getType, "A2").one();
//        if (chargeConfig != null && !"0".equals(chargeConfig.getCharge().trim())) {
//            charge = amount.multiply(new BigDecimal(chargeConfig.getCharge()))
//                    .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
//            if (charge.compareTo(BigDecimal.valueOf(2)) < 0) {
//                charge = BigDecimal.valueOf(2);
//            } else if (charge.compareTo(BigDecimal.valueOf(50)) > 0) {
//                charge = BigDecimal.valueOf(50);
//            }
//        }
//        consumer.accept(charge);
        var alipayConfig = getConfig(user);
        var realName = realnameService.lambdaQuery().eq(RealName::getUserId, user.getId()).one();
        var dateStr = DateUtil.format(new Date(), "yyyyMMdd");

        RAtomicLong atomicLong = redissonClient.getAtomicLong(String.format("EXTRACT_VAL_%s", dateStr));
        var andIncrement = atomicLong.getAndIncrement();
        if (andIncrement == 1L) {
            atomicLong.expire(1, TimeUnit.DAYS);
        }
        AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);
//        String msg = this.doExtraRequest(alipayClient, realName, content, andIncrement);
        BigDecimal limit = new BigDecimal(200000);
        String errmsg = "";
        if (amount.compareTo(limit) > 0) {//有bug
            throw new RuntimeException("提现失败，超过最大限制");
//            BigDecimal times = amount.divide(limit, 0, RoundingMode.UP);
//            BigDecimal extraCharge = charge.divide(times, 2, RoundingMode.HALF_UP);
//            for (int i = 0; i < times.intValue(); i++) {// 201
//                BigDecimal extraAmount = BigDecimal.ZERO;
//                if (amount.compareTo(times.add(BigDecimal.ONE).multiply(limit)) > 0) {
//                    extraAmount = limit;
//                } else {
//                    extraAmount = amount.subtract(times.add(BigDecimal.ONE).multiply(limit));
//                }
//                String msg = this.doExtraRequest(alipayClient, realName,
//                        extraAmount.subtract(extraCharge),
//                        content.getAccount(), andIncrement);
//                if (StrUtil.isEmpty(msg)) {
//                    extra = extra.add(extraAmount);
//                } else {
//                    errmsg = errmsg + msg;
//                    break;
//                }
//            }
//            content.setRemark("已提现：" + extra + "，存在部分提现失败，原因为：" + errmsg);
//            return extra;
        } else {
            String accountId = content.getAccount();
            WithdrawAccount withdrawAccount = withdrawAccountServiceImpl.getById(accountId);
            log.info("===========>amount:{}. charge: {}", amount, charge);
            if (withdrawAccount != null && "2".equals(withdrawAccount.getAccountType())) {
//                String msg = this.doWechatExtraRequest(realName,
//                    amount.subtract(charge),
//                    content.getAccount(), // 这里假设 account 存储的是微信 openid
//                    andIncrement);
//                if (StrUtil.isEmpty(msg)) {
//                    return amount;
//                } else {
//                    errmsg = errmsg + msg;
//                    content.setRemark("提现失败，原因为：" + errmsg);
//                    return extra;
//                }
                return content.getAmount();
            } else {
                String msg = this.doExtraRequest(alipayClient,
                        realName, amount.subtract(charge),
                        withdrawAccount == null ? accountId : withdrawAccount.getAccount(),
                        andIncrement);
                if (StrUtil.isEmpty(msg)) {
                    return amount;
                } else {
                    errmsg = errmsg + msg;
                    content.setRemark("提现失败，原因为：" + errmsg);
                    return extra;
                }
            }
        }
    }



    private String doExtraRequest(AlipayClient alipayClient, RealName realName,
                                  BigDecimal amount, String account,
                                  long andIncrement) throws AlipayApiException {
        // 构造请求参数以调用接口
        AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
        AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
        // 设置商家侧唯一订单号
        model.setOutBizNo(DateUtil.format(new Date(), "yyyyMMdd") + StringUtils.leftPad(andIncrement + "", 4, "0"));
        // 设置订单总金额
        model.setTransAmount(amount.setScale(2, RoundingMode.HALF_UP).toString());
        // 设置描述特定的业务场景
        model.setBizScene("DIRECT_TRANSFER");
        // 设置业务产品码
        model.setProductCode("TRANS_ACCOUNT_NO_PWD");
        // 设置转账业务的标题
        model.setOrderTitle("用户提现");
        // 设置收款方信息
        Participant payeeInfo = new Participant();
        payeeInfo.setCertType("IDENTITY_CARD");
        payeeInfo.setCertNo(realName.getIdNo());
        payeeInfo.setIdentity(account);
        payeeInfo.setName(realName.getRealname());
        payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
        model.setPayeeInfo(payeeInfo);
        // 设置业务备注
        model.setRemark("钱包提现");
        // 设置转账业务请求的扩展参数
        model.setBusinessParams("{\"payer_show_name_use_alias\":\"true\"}");
        request.setBizModel(model);
        AlipayFundTransUniTransferResponse response = alipayClient.certificateExecute(request);
        log.error(JSON.toJSONString(response));
        log.error(response.getSubMsg());
        if (response.isSuccess()) {
            return null;
        } else {
            return ("提现失败： " + response.getSubMsg());
            // sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
            // String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
            // System.out.println(diagnosisUrl);
        }
    }


}
